package nz.ac.massey.jbuif.control;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Collection;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.border.EmptyBorder;

import nz.ac.massey.jbuif.editor.BeanEditor;
import nz.ac.massey.jbuif.events.BeanActionEvent;
import nz.ac.massey.jbuif.events.BeanActionListener;
import nz.ac.massey.jbuif.events.ObjectLoadedEvent;
import nz.ac.massey.jbuif.events.ObjectLoadedListener;
import nz.ac.massey.jbuif.utils.Utils;
import nz.ac.massey.jbuif.view.IView;
import nz.ac.massey.jbuif.view.ListView;

/**
 * JBeanEditor GUI Jpanel
 * @author ahkiouma
 */
public class JBeanEditor extends JFrame implements ObjectLoadedListener,
		BeanActionListener, PropertyChangeListener {

	private static final long serialVersionUID = 3257803429713728620L;
	private static final String JBUIF_EXTENSION = ".jbuif";
	private static final String XML_EXTENSION = ".xml";
	private static final String JAR_EXTENSION = ".jar";
	private static final String EMPTY_EDITOR_TITLE = "No bean in editor.";

	private String[] filters = {"", "\\w.*" , "^[^\\d].*" , "([\\w&&[^b]])*", "[a-zA-Z]{3}, ",
			"([\\w&&[^b]])*", "[^0-9]*[12]?[0-9]{1,2}[^0-9]*"};
	private DefaultComboBoxModel filterModel = new DefaultComboBoxModel(filters);

	private Controller controller;
	private BeanEditor beanEditor;
	private IView view;

	public JBeanEditor() {
		super();

		// create controller
		controller = new Controller();

		// add the view
		view = new ListView();
		view.addBeanActionListener(this);
		controller.setView(view);

		// create components
		initComponents();

		setEnabledControls();

		// add the bean editor
		beanEditor = new BeanEditor();
		beanEditor.setBackground(SystemColor.activeCaptionBorder);
		jpBeanEditorHolder.setBackground(Color.white);
		jpBeanEditorHolder.setLayout(new BorderLayout(0, 0));
		jpBeanEditorHolder.add(beanEditor);

		controller.setBeanEditor(beanEditor);
		beanEditor.addObjectLoadedListener(this);
		beanEditor.addPropertyChangeListener(this);

		// TODO only here for testing
//		controller.loadJar(new File("lib/exampleBeans.jar"));

		this.setTitle("JBUIF - (Java Bean User Interface Framework)");

		// default look and feel selected
		setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
		DefaultLookFeel.setSelected(true);
	}

	/**
	 * setLookAndFeel set the GUI look and feel
	 * @param lnf
	 *            parameter look and feel
	 */
	public void setLookAndFeel(String lnf) {
		// set look and feel
		try {
			UIManager.setLookAndFeel(lnf);

			// update forms components
			SwingUtilities.updateComponentTreeUI(this.getContentPane());

			// update menu bar
			SwingUtilities.updateComponentTreeUI(jMenuBar1);

			DefaultLookFeel.setSelected(false);
			JavaLookFeel.setSelected(false);
			HPLookFeel.setSelected(false);
			WindowsLookFeel.setSelected(false);

			this.pack();
		} catch (Exception e) {
			JOptionPane.showMessageDialog(null, ("Cannot load: " + lnf),
					"JBUIF", JOptionPane.OK_OPTION);
		}
	}

	/**
	 * getBeanCollection get the bean collections
	 * @return the beans as a collection
	 */
	public Collection<Object> getBeanCollection() {
		return controller.getObjects();
	}

	
	/**
	 * toggleEditorBeanBookmark fire event to controller bookmark handeling
	 */
	private void toggleEditorBeanBookmark() {
		boolean toggleState = controller.toggleBookmark();

		if (toggleState) {
			int index = controller.getBookMarkModel().getIndexOf(
					controller.getBeanInEditor());
			cmbxBookmarkedBeans.setSelectedIndex(index);
		}

		setBookmarkState(toggleState);
	}
	
	private void setEditorObjectTitle(String title){
		editorLabel.setText(title);
		editorLabel.setToolTipText(title);
	}

	/**
	 * change the bookmark button face
	 * @param state current state
	 */
	private void setBookmarkState(boolean state) {
		if (state) {
			btnBookmarkBean.setText("Remove Bookmark");
			Utils.setJButtonIcon(btnBookmarkBean, "resources/delete.gif");
		} else {
			btnBookmarkBean.setText("Bookmark");
			Utils.setJButtonIcon(btnBookmarkBean, "resources/add.gif");
		}
	}

	private void LoadJarHandler() {

		JFileChooser fc = new JFileChooser();
		fc.addChoosableFileFilter(new JarFileFilter());
		
		int returnVal = fc.showDialog(this, "Load Jar");

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File file = fc.getSelectedFile();
			
			if(fc.getSelectedFile().getName().toLowerCase().endsWith(".jar"))
			{
				controller.loadJar(file);
			}
			else	
			{
				JOptionPane.showMessageDialog(
						this,
						"The file "+fc.getSelectedFile().getName()+" is not a jar file and cannot be loaded.",
						"Not A Jar File", 1);
			}
		}
	}

	@Override
	public void onBeanAction(BeanActionEvent bae) {
		switch (bae.getBeanAction()) {

		case delete:
			setEditorObjectTitle(EMPTY_EDITOR_TITLE);
			controller.deleteBean(bae.getBean());
			break;

		case edit:
			controller.editBean(bae.getBean());
			break;

		case clone:
			controller.cloneBean(bae.getBean());
			break;
		}
	}

	/**
	 * saveAs the file
	 */
	public File dialog(String msg) {
		String wd = System.getProperty("user.dir");
		JFileChooser fc = new JFileChooser(wd);

		fc.addChoosableFileFilter(new JBUIFFileFilter());
		fc.addChoosableFileFilter(new XMLFileFilter());

		int rc = fc.showDialog(null, msg);
		if (rc == JFileChooser.APPROVE_OPTION) {
			File f = fc.getSelectedFile();
			if ((fc.getFileFilter() instanceof JBUIFFileFilter)
					&& !f.getAbsoluteFile().toString().toLowerCase().endsWith(
							JBUIF_EXTENSION)) {
				f = new File(f.getAbsoluteFile().toString() + JBUIF_EXTENSION);
			} else if ((fc.getFileFilter() instanceof XMLFileFilter)
					&& !f.getAbsoluteFile().toString().toLowerCase().endsWith(
							XML_EXTENSION)) {
				f = new File(f.getAbsoluteFile().toString() + XML_EXTENSION);
			}
			return f;
		} else {
			return null;
		}
	}

	@Override
	public void onObjectLoaded(ObjectLoadedEvent ole) {
		controller.beanLoadedForEditing(ole.getObjectLoaded(), ole
				.getHistoryFlag());
		
//		System.out.println("[L]oaded bean " + ole.getObjectLoaded());
		
		setEditorObjectTitle(ole.getObjectLoaded().toString());
		
		setEnabledControls();
	}

	
	/**
	 * enable the bookmark
	 */
	public void setEnabledControls() {

		if (controller.getBeanInEditor() != null) {
			btnBookmarkBean.setEnabled(true);
			setBookmarkState(controller.getBookmarkStatus());
		} else {
			btnBookmarkBean.setEnabled(false);
		}

		btnHistoryNext.setEnabled(controller.historyHasNext());
		btnHistoryPrev.setEnabled(controller.historyHasPrev());
	}

	private void btnAddNewBeanMouseClicked(MouseEvent evt) {

		if (cmbxBeansAvailable.getItemCount() > 0
				|| cmbxBeansAvailable.getSelectedIndex() != -1) {
			// store the class name of the bean that is to be added
			String beanName = cmbxBeansAvailable.getSelectedItem().toString();

			this.controller.createNewInstanceOfBean(beanName);
		}
	}
	
	/**
	 * initialize the GUI components
	 */
	// <editor-fold defaultstate="collapsed" desc="Generated Code">
	private void initComponents() {
		jTextFieldBox = new JComboBox();
		jTextFieldBox.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent arg0) {
				view.filterList(jTextFieldBox.getSelectedItem().toString());
			}
		});
		jTextFieldBox.setModel(filterModel);
		jTextFieldBox.setEditable(true);
		jTextFieldBox.setToolTipText("Filter list");
		jPanel1 = new javax.swing.JPanel();
		jPanel1.setBorder(new EmptyBorder(0, 0, 4, 4));
		jpBeanView = new javax.swing.JPanel();
		cmbxBeansAvailable = new javax.swing.JComboBox();
		cmbxBeansAvailable.setRenderer(new ComboTooltipRenderer());
		cmbxBeansAvailable.setMaximumRowCount(10);
		jLabel1 = new javax.swing.JLabel();
		jLabel1.setFont(new Font("Segoe UI", Font.BOLD, 13));
		jScrollPane1 = new javax.swing.JScrollPane();
		jLabel2 = new javax.swing.JLabel();
		jLabel2.setFont(new Font("Segoe UI", Font.BOLD, 13));

		btnAddNewBean = new javax.swing.JButton("Add");
		Utils.setJButtonIcon(btnAddNewBean, "resources/arrowdown.gif");
		
		btnAddNewBean.setToolTipText("Add the bean to list");
		btnAddNewBean.setMnemonic(KeyEvent.VK_A);

		jpBeanFilters = new javax.swing.JPanel();
		jFilterLabel = new javax.swing.JLabel();
		
		jFilterLabel.setFont(new Font("Segoe UI", Font.BOLD, 13));
		// cmbxFilter = new javax.swing.JComboBox();
		jpBeanActions = new javax.swing.JPanel();

		btnHistoryPrev = new javax.swing.JButton();
		btnHistoryPrev.setToolTipText("Previous history");
		btnHistoryPrev.setHorizontalAlignment(SwingConstants.LEFT);
		Utils.setJButtonIcon(btnHistoryPrev, "resources/prev.gif");
		
		btnHistoryNext = new javax.swing.JButton();
		Utils.setJButtonIcon(btnHistoryNext, "resources/next.gif");
		
		btnHistoryNext.setToolTipText("Next history");
		btnHistoryNext.setHorizontalAlignment(SwingConstants.LEFT);

		historyLabel = new javax.swing.JLabel();
		historyLabel.setFont(new Font("Segoe UI", Font.BOLD, 13));
		cmbxBookmarkedBeans = new javax.swing.JComboBox();
		btnBookmarkBean = new javax.swing.JButton("Bookmark");
		Utils.setJButtonIcon(btnBookmarkBean, "resources/add.gif");
		btnBookmarkBean.setToolTipText("Bookmark a bean");

		new JScrollPane();
		jpBeanEditorHolder = new javax.swing.JPanel();

		jMenuBar1 = new JMenuBar();
		mnuFile = new JMenu();
		mnuiNew = new JMenuItem("New");
		Utils.setJMenuItemIcon(mnuiNew, "resources/new.gif");
		
		mnuiOpen = new JMenuItem("Open");
		Utils.setJMenuItemIcon(mnuiOpen, "resources/open.gif");
		
		mnuiSave = new JMenuItem("Save");
		Utils.setJMenuItemIcon(mnuiSave, "resources/save.gif");
		
		mnuiSaveAs = new JMenuItem("Save As...");
		Utils.setJMenuItemIcon(mnuiSaveAs, "resources/saveas.gif");
		
		mnuiExit = new JMenuItem("Exit");

		mnuiLooknFeel = new JMenu();

		DefaultLookFeel = new javax.swing.JRadioButtonMenuItem();
		WindowsLookFeel = new javax.swing.JRadioButtonMenuItem();
		HPLookFeel = new javax.swing.JRadioButtonMenuItem();
		JavaLookFeel = new javax.swing.JRadioButtonMenuItem();

		mnuBeans = new JMenu("Beans");
		mnuiLoadJar = new JMenuItem("Load Jar File");
		Utils.setJMenuItemIcon(mnuiLoadJar, "resources/loadjar.gif");

		setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

		// create new - left panel - border disable by default
		jpBeanView.setBorder(javax.swing.BorderFactory
				.createEtchedBorder(javax.swing.border.BevelBorder.RAISED));

		cmbxBeansAvailable.setModel(controller.getBeansAvailableModel());

		cmbxBeansAvailable.setName("cmbxObjectsAvailable");

		jLabel1.setText("Create New");

		jLabel2.setText("Components");

		JViewport objectView = new JViewport();
		objectView.setView((Component) view);
		jScrollPane1.setViewportView(objectView);

		btnAddNewBean.setName("btnAddNewObject"); // NOI18N
		btnAddNewBean.addMouseListener(new java.awt.event.MouseAdapter() {
			public void mouseClicked(java.awt.event.MouseEvent evt) {
				btnAddNewBeanMouseClicked(evt);
			}
		});

		// HISTORY RELATED LISTENERS
		btnHistoryPrev.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				controller.prevInHistory();
				setEnabledControls();
			}
		});

		btnHistoryNext.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				controller.nextInHistory();
				setEnabledControls();
			}
		});

		cmbxBookmarkedBeans.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JComboBox cb = (JComboBox) e.getSource();
				Object selectedBean = cb.getSelectedItem();

//				System.out.println("bookmark: selected index="+cb.getSelectedIndex());
				if (cb.getSelectedIndex() != -1
						&& !controller.getBeanInEditor().equals(selectedBean)) {
					// a book mark has been selected, so load it
					controller.editBean(selectedBean);
//					System.out.println("[E]diting bean " + selectedBean);
				}
			}
		});

		lblDoubleClickOn = new JLabel(
				"Dbl click to open in editor/Right click for properties");
		lblDoubleClickOn.setFont(new Font("Arial", Font.ITALIC, 11));

		javax.swing.GroupLayout gl_jpBeanView = new javax.swing.GroupLayout(
				jpBeanView);
		gl_jpBeanView
				.setHorizontalGroup(gl_jpBeanView
						.createParallelGroup(Alignment.TRAILING)
						.addGroup(
								gl_jpBeanView
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												gl_jpBeanView
														.createParallelGroup(
																Alignment.LEADING)
														.addComponent(
																jScrollPane1,
																Alignment.TRAILING,
																GroupLayout.PREFERRED_SIZE,
																262,
																Short.MAX_VALUE)
														.addGroup(
																Alignment.TRAILING,
																gl_jpBeanView
																		.createSequentialGroup()
																		.addGroup(
																				gl_jpBeanView
																						.createParallelGroup(
																								Alignment.TRAILING)
																						.addComponent(
																								jLabel2,
																								Alignment.LEADING)
																						.addComponent(
																								cmbxBeansAvailable,
																								0,
																								205,
																								Short.MAX_VALUE))
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				btnAddNewBean))
														.addComponent(
																lblDoubleClickOn)
														.addComponent(jLabel1))
										.addContainerGap()));
		gl_jpBeanView
				.setVerticalGroup(gl_jpBeanView
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								gl_jpBeanView
										.createSequentialGroup()
										.addGap(33)
										.addComponent(jLabel1)
										.addPreferredGap(
												ComponentPlacement.RELATED)
										.addGroup(
												gl_jpBeanView
														.createParallelGroup(
																Alignment.TRAILING)
														.addGroup(
																gl_jpBeanView
																		.createSequentialGroup()
																		.addGroup(
																				gl_jpBeanView
																						.createParallelGroup(
																								Alignment.BASELINE)
																						.addComponent(
																								btnAddNewBean)
																						.addComponent(
																								cmbxBeansAvailable,
																								GroupLayout.PREFERRED_SIZE,
																								GroupLayout.DEFAULT_SIZE,
																								GroupLayout.PREFERRED_SIZE))
																		.addGap(
																				37))
														.addGroup(
																gl_jpBeanView
																		.createSequentialGroup()
																		.addComponent(
																				jLabel2)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)))
										.addPreferredGap(
												ComponentPlacement.RELATED)
										.addComponent(lblDoubleClickOn)
										.addPreferredGap(
												ComponentPlacement.RELATED)
										.addComponent(jScrollPane1,
												GroupLayout.DEFAULT_SIZE, 425,
												Short.MAX_VALUE)
										.addContainerGap()));
		jpBeanView.setLayout(gl_jpBeanView);

		// filter - left panel - panel border disable by default
		jpBeanFilters.setBorder(javax.swing.BorderFactory
				.createEtchedBorder(javax.swing.border.BevelBorder.RAISED));

		jFilterLabel.setText("Filter");

		button = new JButton("");
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (!jTextFieldBox.getSelectedItem().equals("")) {
					filterModel.removeElement(jTextFieldBox.getSelectedItem());
					jTextFieldBox.setSelectedItem("");
				} else
					JOptionPane
							.showMessageDialog(
									null,
									"No filter is selected. \n"
											+ "To remove a filter, it must be selected first.",
									"Filter...", 1);
			}
		});
		button.setToolTipText("Remove the filter from the list");
		Utils.setJButtonIcon(button, "resources/delete.gif");

		button_1 = new JButton("");
		button_1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				boolean flag = false;
				boolean correctPattern = true;
				
				try{
					Pattern.compile(jTextFieldBox.getSelectedItem().toString());
				}
				catch (PatternSyntaxException e){
					JOptionPane.showMessageDialog(null, 
							"<html><b>Regular expression is not valid !","Regex...",JOptionPane.OK_OPTION);
					correctPattern = false;
				}
				
				if (correctPattern){
					for (int i = 0; i < filterModel.getSize(); i++) {
						if (filterModel.getElementAt(i).equals(
								jTextFieldBox.getSelectedItem()))
							flag = true;
					}
					if (!flag) {
						filterModel.addElement(jTextFieldBox.getSelectedItem());
						jTextFieldBox.setSelectedItem("");
					} else if (jTextFieldBox.getSelectedItem().equals(""))
						JOptionPane.showMessageDialog(null, "No filter defined. "
								+ "	", "Filter...", 1);
					else {
						JOptionPane.showMessageDialog(null,
								"Filter is already exists.",
								"Filter...", 1);
					}
				}
			}
		});
		button_1.setToolTipText("Add the filter to list");
		Utils.setJButtonIcon(button_1, "resources/add.gif");

		javax.swing.GroupLayout gl_jpBeanFilters = new javax.swing.GroupLayout(
				jpBeanFilters);
		gl_jpBeanFilters.setHorizontalGroup(gl_jpBeanFilters
				.createParallelGroup(Alignment.TRAILING).addGroup(
						gl_jpBeanFilters.createSequentialGroup()
								.addContainerGap(11, Short.MAX_VALUE)
								.addComponent(jFilterLabel).addPreferredGap(
										ComponentPlacement.UNRELATED)
								.addComponent(jTextFieldBox,
										GroupLayout.PREFERRED_SIZE, 154,
										GroupLayout.PREFERRED_SIZE).addGap(1)
								.addComponent(button_1,
										GroupLayout.PREFERRED_SIZE, 30,
										GroupLayout.PREFERRED_SIZE).addGap(2)
								.addComponent(button,
										GroupLayout.PREFERRED_SIZE, 30,
										GroupLayout.PREFERRED_SIZE).addGap(6)));
		gl_jpBeanFilters
				.setVerticalGroup(gl_jpBeanFilters
						.createParallelGroup(Alignment.TRAILING)
						.addGroup(
								gl_jpBeanFilters
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												gl_jpBeanFilters
														.createParallelGroup(
																Alignment.TRAILING)
														.addGroup(
																gl_jpBeanFilters
																		.createSequentialGroup()
																		.addGroup(
																				gl_jpBeanFilters
																						.createParallelGroup(
																								Alignment.TRAILING)
																						.addComponent(
																								button)
																						.addComponent(
																								button_1,
																								Alignment.LEADING))
																		.addGap(
																				14))
														.addGroup(
																gl_jpBeanFilters
																		.createSequentialGroup()
																		.addGroup(
																				gl_jpBeanFilters
																						.createParallelGroup(
																								Alignment.BASELINE)
																						.addComponent(
																								jFilterLabel)
																						.addComponent(
																								jTextFieldBox,
																								GroupLayout.PREFERRED_SIZE,
																								26,
																								GroupLayout.PREFERRED_SIZE))
																		.addGap(
																				14)))));
		jpBeanFilters.setLayout(gl_jpBeanFilters);

		jpBeanActions.setBorder(javax.swing.BorderFactory
				.createEtchedBorder(javax.swing.border.BevelBorder.LOWERED));

		btnHistoryPrev.setName("btnHistoryPrev");
		btnHistoryNext.setName("btnHistoryNext");

		historyLabel.setText("History Item");

		cmbxBookmarkedBeans.setModel(controller.getBookMarkModel());
		cmbxBookmarkedBeans.setName("cmbxBookmarkedBeans");
		
		lblBookmark = new JLabel();
		lblBookmark.setText("Bookmarks");
		lblBookmark.setFont(new Font("Segoe UI", Font.BOLD, 13));

		javax.swing.GroupLayout gl_jpBeanActions = new javax.swing.GroupLayout(
				jpBeanActions);
		gl_jpBeanActions.setHorizontalGroup(
			gl_jpBeanActions.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_jpBeanActions.createSequentialGroup()
					.addContainerGap()
					.addComponent(historyLabel)
					.addGap(10)
					.addComponent(btnHistoryPrev)
					.addGap(1)
					.addComponent(btnHistoryNext)
					.addPreferredGap(ComponentPlacement.RELATED, 373, Short.MAX_VALUE)
					.addComponent(lblBookmark, GroupLayout.PREFERRED_SIZE, 72, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(cmbxBookmarkedBeans, GroupLayout.PREFERRED_SIZE, 225, GroupLayout.PREFERRED_SIZE)
					.addContainerGap())
		);
		gl_jpBeanActions.setVerticalGroup(
			gl_jpBeanActions.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_jpBeanActions.createSequentialGroup()
					.addContainerGap()
					.addGroup(gl_jpBeanActions.createParallelGroup(Alignment.TRAILING)
						.addGroup(gl_jpBeanActions.createParallelGroup(Alignment.BASELINE)
							.addComponent(cmbxBookmarkedBeans, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
							.addComponent(lblBookmark, GroupLayout.PREFERRED_SIZE, 18, GroupLayout.PREFERRED_SIZE))
						.addGroup(gl_jpBeanActions.createParallelGroup(Alignment.LEADING, false)
							.addComponent(historyLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
							.addComponent(btnHistoryNext, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
							.addComponent(btnHistoryPrev, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
					.addContainerGap(18, Short.MAX_VALUE))
		);
		jpBeanActions.setLayout(gl_jpBeanActions);

		JPanel imageTextPanel = new JPanel();

		JScrollPane verticalPane;

		verticalPane = new JScrollPane(imageTextPanel, // component
				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, // vertical bar
				JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); // assuming you only
		// need
		final JFrame frame = new JFrame();

		frame.getContentPane().add(verticalPane);

		jpBeanEditorHolder.setBorder(javax.swing.BorderFactory
				.createBevelBorder(javax.swing.border.BevelBorder.RAISED));

		jpBeanEditorScrollHolder_1 = new JScrollPane(jpBeanEditorHolder, // component
				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, // vertical bar
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		
		editorLabel = new JLabel(EMPTY_EDITOR_TITLE);
		// editorLabel.setIcon(new ImageIcon("resources/editor.gif"));
		editorLabel.setHorizontalAlignment(SwingConstants.LEFT);
		editorLabel.setFont(new Font("Segoe UI", Font.BOLD, 14));
		btnBookmarkBean = new javax.swing.JButton("Bookmark");
		Utils.setJButtonIcon(btnBookmarkBean, "resources/add.gif");
		btnBookmarkBean.setToolTipText("Bookmark a bean");
		
				// BOOKMARK RELATED LISTENERS
				btnBookmarkBean.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						toggleEditorBeanBookmark();
					}
				});
				
					btnBookmarkBean.setName("btnBookmark");
		// need

		// jpBeanEditorHolder.setLayout(new BorderLayout());

		javax.swing.GroupLayout gl_jPanel1 = new javax.swing.GroupLayout(
				jPanel1);
		gl_jPanel1.setHorizontalGroup(
			gl_jPanel1.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_jPanel1.createSequentialGroup()
					.addGroup(gl_jPanel1.createParallelGroup(Alignment.LEADING, false)
						.addComponent(jpBeanFilters, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
						.addComponent(jpBeanView, GroupLayout.PREFERRED_SIZE, 286, Short.MAX_VALUE))
					.addGap(18)
					.addGroup(gl_jPanel1.createParallelGroup(Alignment.TRAILING)
						.addGroup(gl_jPanel1.createSequentialGroup()
							.addComponent(editorLabel, GroupLayout.DEFAULT_SIZE, 756, Short.MAX_VALUE)
							.addGap(18)
							.addComponent(btnBookmarkBean))
						.addComponent(jpBeanEditorScrollHolder_1, GroupLayout.DEFAULT_SIZE, 861, Short.MAX_VALUE)
						.addComponent(jpBeanActions, GroupLayout.DEFAULT_SIZE, 861, Short.MAX_VALUE))
					.addContainerGap())
		);
		gl_jPanel1.setVerticalGroup(
			gl_jPanel1.createParallelGroup(Alignment.TRAILING)
				.addGroup(gl_jPanel1.createSequentialGroup()
					.addGroup(gl_jPanel1.createParallelGroup(Alignment.LEADING)
						.addGroup(gl_jPanel1.createSequentialGroup()
							.addComponent(jpBeanActions, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
							.addPreferredGap(ComponentPlacement.RELATED)
							.addGroup(gl_jPanel1.createParallelGroup(Alignment.TRAILING)
								.addComponent(btnBookmarkBean)
								.addComponent(editorLabel))
							.addPreferredGap(ComponentPlacement.RELATED)
							.addComponent(jpBeanEditorScrollHolder_1, GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
						.addGroup(gl_jPanel1.createSequentialGroup()
							.addComponent(jpBeanView, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
							.addPreferredGap(ComponentPlacement.RELATED)
							.addComponent(jpBeanFilters, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
					.addGap(13))
		);
		jPanel1.setLayout(gl_jPanel1);

		mnuFile.setText("File");

		// create a new project by calling newProject() in controller
		// mnuiNew.setText("New");
		mnuiNew.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {

				// if user confirmed to create a new project
				if (JOptionPane
						.showConfirmDialog(
								null,
								("Creating a new project will cause unsaved chances to be lost"
										+ "\nAre you sure you want to create a new project ?"),
								"JBUIF: New Project", JOptionPane.YES_NO_OPTION) == 0) {

					controller.newProject();
					setEnabledControls();
				}
			}
		});

		mnuiNew.setMnemonic(KeyEvent.VK_N);
		mnuiNew.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
				InputEvent.CTRL_MASK));
		mnuFile.add(mnuiNew);

		mnuiLoadJar.setMnemonic(KeyEvent.VK_J);
		mnuiLoadJar.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_J,
				InputEvent.CTRL_MASK));
		mnuBeans.add(mnuiLoadJar);

		// load a project by calling loadObjects() in controller
		mnuiOpen.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				File file = dialog("Load");

				if (file != null) {
					controller.loadObjects(file);
					setEnabledControls();
				}
			}
		});

		mnuiOpen.setMnemonic(KeyEvent.VK_O);
		mnuiOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
				InputEvent.CTRL_MASK));
		mnuFile.add(mnuiOpen);

		mnuFile.addSeparator();

		// save
		mnuiSave.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				// get the file name, if it exists.
				File file = controller.getFileName();

				// if reserved (means save as performed, then do the save,
				// otherwise call the save as)
				if (file != null) {
					controller.saveObjects(file);
				} else {
					controller.saveObjects(dialog("Save As..."));
				}
			}
		});
		mnuiSave.setMnemonic(KeyEvent.VK_S);
		mnuiSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
				InputEvent.CTRL_MASK));
		mnuFile.add(mnuiSave);

		// saveAs
		mnuiSaveAs.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				// call the save as method
				controller.saveObjects(dialog("Save As..."));
			}
		});
		mnuFile.add(mnuiSaveAs);

		mnuFile.addSeparator();

		mnuFile.setMnemonic(KeyEvent.VK_F);

		mnuiExit.setMnemonic(KeyEvent.VK_X);
		mnuiExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,
				InputEvent.ALT_MASK));

		mnuFile.add(mnuiExit);

		mnuBeans.setMnemonic(KeyEvent.VK_B);

		mnuiLoadJar.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
//				System.out.println("Load Jar File clicked.");
				LoadJarHandler();
			}
		});
		mnuBeans.add(mnuiLoadJar);

		mnuiExit.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent me) {

				// exit message box dialog
				if (JOptionPane.showConfirmDialog(null,
						"Are you sure you want to exit ?", "JBUIF: Exit",
						JOptionPane.YES_NO_OPTION) == 0)

					System.exit(0);
			}
		});

		mnuiLooknFeel.setText("Look and Feel");
		mnuiLooknFeel.setMnemonic(KeyEvent.VK_L);

		DefaultLookFeel.setText("Nimbus");
		DefaultLookFeel.addMouseListener(new java.awt.event.MouseAdapter() {
			public void mousePressed(java.awt.event.MouseEvent evt) {
				setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
			}
		});

		HPLookFeel.setText("Metal");
		HPLookFeel.addMouseListener(new java.awt.event.MouseAdapter() {
			public void mousePressed(java.awt.event.MouseEvent evt) {
				setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
			}
		});

		JavaLookFeel.setText("Motif");
		JavaLookFeel.addMouseListener(new java.awt.event.MouseAdapter() {
			public void mousePressed(java.awt.event.MouseEvent evt) {
				setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
			}
		});

		WindowsLookFeel.setText("Windows");
		WindowsLookFeel.addMouseListener(new java.awt.event.MouseAdapter() {
			public void mousePressed(java.awt.event.MouseEvent evt) {
				setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
			}
		});

		//
		// look and feel items
		mnuiLooknFeel.add(DefaultLookFeel);
		mnuiLooknFeel.add(HPLookFeel);
		mnuiLooknFeel.add(JavaLookFeel);
		mnuiLooknFeel.add(WindowsLookFeel);

		jMenuBar1.add(mnuFile);
		jMenuBar1.add(mnuBeans);
		jMenuBar1.add(mnuiLooknFeel);

		setJMenuBar(jMenuBar1);
		
		label = new JLabel(".");

		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(
				getContentPane());
		layout.setHorizontalGroup(
			layout.createParallelGroup(Alignment.TRAILING)
				.addComponent(jPanel1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
				.addGroup(layout.createSequentialGroup()
					.addContainerGap(783, Short.MAX_VALUE)
					.addComponent(label)
					.addGap(395))
		);
		layout.setVerticalGroup(
			layout.createParallelGroup(Alignment.LEADING)
				.addGroup(layout.createSequentialGroup()
					.addComponent(jPanel1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(label))
		);
		getContentPane().setLayout(layout);

		pack();
	}// </editor-fold>

	// Variables declaration - do not modify
	private javax.swing.JButton btnAddNewBean;
	private javax.swing.JButton btnBookmarkBean;
	private javax.swing.JButton btnHistoryNext;
	private javax.swing.JButton btnHistoryPrev;
	private javax.swing.JComboBox cmbxBeansAvailable;
	private javax.swing.JComboBox cmbxBookmarkedBeans;
	private javax.swing.JLabel jLabel1;
	private javax.swing.JLabel jLabel2;
	private javax.swing.JLabel jFilterLabel;
	private javax.swing.JMenuBar jMenuBar1;
	private javax.swing.JPanel jPanel1;
	private javax.swing.JScrollPane jScrollPane1;
	private javax.swing.JPanel jpBeanActions;
	private JScrollPane jpBeanEditorScrollHolder_1;
	private javax.swing.JPanel jpBeanEditorHolder;
	private javax.swing.JPanel jpBeanFilters;
	private javax.swing.JPanel jpBeanView;
	private javax.swing.JLabel historyLabel;
	private javax.swing.JMenu mnuFile;
	private javax.swing.JMenu mnuiLooknFeel;
	private javax.swing.JMenuItem mnuiExit;
	@SuppressWarnings("unused")
	private javax.swing.JMenuItem mnuiLoad;
	private javax.swing.JMenuItem mnuiOpen;
	private javax.swing.JMenuItem mnuiNew;
	private javax.swing.JMenuItem mnuiSaveAs;
	private javax.swing.JMenuItem mnuiSave;
	private JComboBox jTextFieldBox;
	private javax.swing.JMenu mnuBeans;
	private javax.swing.JMenuItem mnuiLoadJar;

	private javax.swing.JRadioButtonMenuItem DefaultLookFeel;
	private javax.swing.JRadioButtonMenuItem HPLookFeel;
	private javax.swing.JRadioButtonMenuItem JavaLookFeel;
	private javax.swing.JRadioButtonMenuItem WindowsLookFeel;
	private JButton button;
	private JButton button_1;
	private JLabel lblDoubleClickOn;
	private JLabel lblBookmark;
	private JLabel label;
	private JLabel editorLabel;
	
	// End of variables declaration

	/**
	 * @param args
	 *            the command line arguments
	 */
	public static void main(String args[]) {
		java.awt.EventQueue.invokeLater(new Runnable() {
			public void run() {
				new JBeanEditor().setVisible(true);
			}
		});
	}

	class XMLFileFilter extends javax.swing.filechooser.FileFilter {
		public boolean accept(File file) {
			String filename = file.getName();
			return filename.toLowerCase().endsWith(XML_EXTENSION) || file.isDirectory();
		}

		public String getDescription() {
			return "*"+XML_EXTENSION;
		}
	}

	class JBUIFFileFilter extends javax.swing.filechooser.FileFilter {
		public boolean accept(File file) {
			String filename = file.getName();
			return filename.toLowerCase().endsWith(JBUIF_EXTENSION) || file.isDirectory();
		}

		public String getDescription() {
			return "*"+JBUIF_EXTENSION;
		}
	}
	
	class JarFileFilter extends javax.swing.filechooser.FileFilter {
		public boolean accept(File file) {
			String filename = file.getName();
			return filename.toLowerCase().endsWith(JAR_EXTENSION) || file.isDirectory();
		}

		public String getDescription() {
			return "*"+JAR_EXTENSION;
		}
	}

	public class ComboTooltipRenderer extends DefaultListCellRenderer {

		private static final long serialVersionUID = -2282362529161741000L;

		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
			JComponent comp = (JComponent) super.getListCellRendererComponent(
					list, value, index, isSelected, cellHasFocus);

			if (value != null) {
				comp.setToolTipText(String.valueOf(value));
			} else {
				comp.setToolTipText(null);
			}
			return comp;
		}
	}

	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		if(evt.getSource() == controller.editor && "EditedBean".equals(evt.getPropertyName()))
		{
//			System.out.println("[P]roperty change event for "+evt.getPropertyName() +"{ "+evt.getNewValue()+" }");
			setEditorObjectTitle(evt.getNewValue().toString());
			controller.reloadView();
			view.filterList(jTextFieldBox.getSelectedItem().toString());
		}
		view.refreshView();
	}
}
